package com.example.friend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.example.core.constants.CacheConstants;
import com.example.core.constants.Constants;
import com.example.core.domain.LoginUser;
import com.example.core.enums.UserIdentity;
import com.example.core.utils.StringUtils;
import com.example.core.utils.VerifyUtils;
import com.example.friend.domain.User;
import com.example.friend.domain.dto.UserDTO;
import com.example.friend.domain.dto.UserUpdateDTO;
import com.example.friend.domain.vo.UserVO;
import com.example.friend.manger.UserCacheManager;
import com.example.friend.mapper.UserMapper;
import com.example.friend.service.IUserService;
import com.example.message.service.AliSmsService;
import com.example.redis.service.RedisService;
import com.example.scurity.exception.ServiceException;
import com.example.scurity.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserCacheManager userCacheManager;

    @Autowired
    private RedisService redisService;

    @Autowired
    private AliSmsService aliSmsService;

    @Value("${sms.send-limit:5}")
    private Integer sendLimit;

    @Value("${sms.code-expiration:}")
    private Long phoneCodeExpiration;

    @Value("${sms.send-message:false}")
    private boolean sendMessage;

    @Override
    public LoginUser login(UserDTO loginDTO) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserAccount, loginDTO.getUserAccount()));
        if (user == null) {
            throw new ServiceException("当前登录用户不存在");
        }
        if (!SecurityUtils.matchesPassword(loginDTO.getPassword(), user.getPassword())) {
            throw new ServiceException("账号或密码错误");
        }
//        if (!Md5Utils.verifyOriginalAndCiphertext(loginDTO.getPassword(), user.getSalt(), user.getPassword())) {
//            throw new ServiceException("账号或密码错误");
//        }
        //通过账号查找用户
        return assembleLoginUser(user);
    }

    @Override
    public LoginUser codeLogin(UserDTO loginDTO) {
        checkCode(loginDTO.getPhone(), loginDTO.getCode());
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getUserId)
                .eq(User::getPhone, loginDTO.getPhone()));
        if (user == null) {
            //先注册
            user = new User();
            BeanUtils.copyProperties(loginDTO, user);
            user.setUserAccount(loginDTO.getPhone());
            userMapper.insert(user);
        }
        return assembleLoginUser(user);
    }

    private void checkCode(String phone, String code) {
        //校验验证码
        String cacheKey = CacheConstants.PHONE_CODE_KEY + phone;
        String cacheValue = redisService.getCacheObject(cacheKey, String.class);
        if (StringUtils.isEmpty(cacheValue)) {
            throw new ServiceException("验证码无效");
        }
        if (!cacheValue.equals(code)) {
            throw new ServiceException("验证码错误");
        }
        //删除缓存
        redisService.deleteObject(cacheKey);
    }

    @Override
    public int register(UserDTO registerDTO) {
        User user = assembleSysUserByBCrypt(registerDTO);
        return userMapper.insert(user);
    }

    @Override
    public boolean sendCode(String phone) {
        if (!VerifyUtils.checkPhone(phone)) {
            throw new ServiceException("手机号格式错误");
        }
        //校验是否超过每日限制
        String limitCacheKey = CacheConstants.PHONE_CODE_TIMES_KEY + phone;
        Integer times = redisService.getCacheObject(limitCacheKey, Integer.class);
        times = times == null ? 0 : times;
        if (times >= 10000) {
            throw new ServiceException("超过每日发送次数限制");
        }

        //校验是否在1分钟之内频繁发送
        String cacheKey = CacheConstants.PHONE_CODE_KEY + phone;
        String cacheValue = redisService.getCacheObject(cacheKey, String.class);
        long expireTime = redisService.getExpire(cacheKey);
        if (!StringUtils.isEmpty(cacheValue) && expireTime > phoneCodeExpiration * 60 - 60) {
            long time = expireTime - (phoneCodeExpiration * 60 - 60);
            throw new ServiceException("操作频繁，请在" + time + "秒之后再试");
        }
        // 生成验证码
        String verifyCode = sendMessage ? VerifyUtils.generateNumberVerifyCode(6) : Constants.DEFAULT_CODE;
//        verifyCode = "262772";

        //将验证码和验证码的发送次数存储到redis
//        if (sendMessage) {
//            boolean sendMobile = aliSmsService.sendMobileCode(phone, verifyCode);
//            if (!sendMobile) {
//                throw new ServiceException("短信发送失败");
//            }
//        }
        redisService.setCacheObject(cacheKey, verifyCode, phoneCodeExpiration, TimeUnit.MINUTES);

        long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(),
                LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0));
        redisService.setCacheObject(limitCacheKey, times + 1, seconds, TimeUnit.SECONDS);
        return true;
    }

    @Override
    public UserVO getSimpleUserInfo(Long userId) {
        if (userId == null) {
            userId = SecurityUtils.getUserId();
        }
        if (userId == null) {
            throw new ServiceException("请您先登录再查看个人信息");
        }
        User user = userCacheManager.getUserById(userId);
        UserVO userVO = new UserVO();
        userVO.setNickName(user.getNickName());
//        userVO.setHeadImage(user.getHeadImage());
        return userVO;
    }

//    初始版本
//    public UserVO getSimpleUserInfo() {
//        LoginUser loginUser = SecurityUtils.getLoginUser();
//        if (loginUser == null) {
//            throw new ServiceException("请您先登录再查看个人信息");
//        }
//        UserVO userVO = new UserVO();
//        userVO.setNickName(loginUser.getNickName());
//        return userVO;
//    }

    @Override
    public UserVO detail(Long userId) {
        if (userId == null) {
            userId = SecurityUtils.getUserId();
        }
        if (userId == null) {
            throw new ServiceException("请您先登录再查看个人信息");
        }
        User user = userCacheManager.getUserById(userId);
        UserVO userVO = new UserVO();
        if (user != null) {
            BeanUtils.copyProperties(user, userVO);
        }
        userVO.setHeadImage(null);
        return userVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean edit(UserUpdateDTO userUpdateDTO) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("请您先登录再修改个人信息");
        }
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new ServiceException("当前用户不存在");
        }
        user.setIntroduce(userUpdateDTO.getIntroduce());
        user.setNickName(userUpdateDTO.getNickName());
        user.setEmail(userUpdateDTO.getEmail());
        user.setPhone(userUpdateDTO.getPhone());
        user.setSex(userUpdateDTO.getSex());
        user.setWechat(userUpdateDTO.getWechat());
        user.setMajorName(userUpdateDTO.getMajorName());
        user.setSchoolName(userUpdateDTO.getSchoolName());
        //更新用户缓存
        userCacheManager.refreshUser(user);

        return userMapper.updateById(user) > 0;
    }

    @Override
    public boolean checkUserInfoUnique(UserDTO registerDTO) {
        List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>()
                .eq(User::getUserAccount, registerDTO.getUserAccount()));
        return CollectionUtils.isEmpty(userList);
    }

    @Override
    public int updatePasswd(String userAccount) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserAccount, userAccount));
        String passwordInDB = SecurityUtils.encryptPassword("user@123");
        user.setPassword(passwordInDB);
        return userMapper.updateById(user);
    }

    @Override
    public int uploadHeadImage(String headImage) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("用户不存在");
        }
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new ServiceException("用户不存在");
        }
        user.setHeadImage(headImage);
        //更新用户缓存
        userCacheManager.refreshUser(user);
        //更新数据库
        return userMapper.updateById(user);
    }

    /**
     * 使用md5加密
     * @param registerDTO
     * @return
     */
//    private User assembleUser(UserDTO registerDTO) {
//        User user = new User();
//        BeanUtils.copyProperties(registerDTO, user);
//        String salt = UUIDUtils.simpleUUID();
//        user.setSalt(salt);
//        String passwordInDB = Md5Utils.md5Salt(registerDTO.getPassword(), salt);
//        user.setPassword(passwordInDB);
//        return user;
//    }

    /**
     * 使用BCrypt加密
     *
     * @param registerDTO
     * @return
     */
    private User assembleSysUserByBCrypt(UserDTO registerDTO) {
        User user = new User();
        BeanUtils.copyProperties(registerDTO, user);
        String passwordInDB = SecurityUtils.encryptPassword(registerDTO.getPassword());
        user.setPassword(passwordInDB);
        return user;
    }

    private LoginUser assembleLoginUser(User user) {
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(user, loginUser);
        loginUser.setIdentity(UserIdentity.USER.getValue());
        return loginUser;
    }
}
